package ObjetoBr;

import java.util.Scanner;
import java.util.ArrayList;

public class AnalisadorLexico{

	private enum EstadoIntermediario{
		INICIO,
	
		/* Identificadores */
		RECONHECENDO_IDENTIFICADOR,

		/* Digitos */
		RECONHECENDO_INTEIRO,
		RECONHECENDO_REAL,

		/* Texto */
		RECONHECENDO_TEXTO,
		ESCAPANDO_TEXTO,

		/* Aritimeticos */
		RECONHECENDO_MAIS,
		RECONHECENDO_MENOS,
		RECONHECENDO_VEZES,
		RECONHECENDO_DIVIDIDO,

		/* Logico */
		RECONHECENDO_E,
		RECONHECENDO_OU,
		RECONHECENDO_NAO,

		/* Caso da exclamacao */
		RECONHECENDO_EXCLAMACAO,

		/* De Comparacao */
		RECONHECENDO_MENOR,
		RECONHECENDO_IGUAL,
		RECONHECENDO_MAIOR,

		RECONHECENDO_COMENTARIO_A,
		RECONHECENDO_COMENTARIO_B,

		/* Erro */
		ERRO
	}


	public static void main(String[] args){
		
		ArrayList<Ficha> fichas = new ArrayList<Ficha>();
		StringBuffer reconhecido = new StringBuffer();
		Leitor l = new Leitor("Codigo.br");


		int p_atual=0;
		EstadoIntermediario estado = EstadoIntermediario.INICIO;

		int ficha_inicio=0;
		char c;
		
		boolean salvar = true;
		
		estado = EstadoIntermediario.INICIO;

		while(l.temProximo()) {
			
			c = l.proximoCaracter();
			
			switch(estado) {
				case INICIO:
					// PULAR:
					if(c == ' ' || c < 20){
						break;
					}

					reconhecido = new StringBuffer();
					salvar = true;

					if ( (c > 0x40 && c < 0x5B) || (c > 0x60 && c < 0x7B) || c == '_' ) {
						estado = EstadoIntermediario.RECONHECENDO_IDENTIFICADOR;
					}

					// Inicio do reconhecimento de constante_texto
					else if(c == '"'){
						estado = EstadoIntermediario.RECONHECENDO_TEXTO;
						salvar = false;
					}

					else if (c > 0x2F && c < 0x3A) {
						estado = EstadoIntermediario.RECONHECENDO_INTEIRO;
						ficha_inicio = p_atual;
					}

					// Inicio do reconhecimento de operadores aritimeticos
					else if (c == '+') {
						estado = EstadoIntermediario.RECONHECENDO_MAIS;
						ficha_inicio = p_atual;
					}

					else if (c == '-') {
						estado = EstadoIntermediario.RECONHECENDO_MENOS;
						ficha_inicio = p_atual;
					}

					else if (c == '*') {
						estado = EstadoIntermediario.RECONHECENDO_VEZES;
						ficha_inicio = p_atual;
					}

					else if (c == '/') {
						estado = EstadoIntermediario.RECONHECENDO_DIVIDIDO;
						ficha_inicio = p_atual;
					}

					else if (c == '%') {
						fichas.add(new Ficha(TipoFicha.RESTO, 0, 0 ,0 ,0, "%"));
					}

					else if (c == '@') {
						fichas.add(new Ficha(TipoFicha.ELEVADO, 0, 0 ,0 ,0, "@"));
					}

					else if (c == '#') {
						fichas.add(new Ficha(TipoFicha.RAIZ, 0, 0 ,0 ,0, "#"));
					}

					else if (c == '{') {
						fichas.add(new Ficha(TipoFicha.CHAVE_ESQUERDA, 0, 0 ,0 ,0, "{"));
					}

					else if (c == '}') {
						fichas.add(new Ficha(TipoFicha.CHAVE_DIREITA, 0, 0 ,0 ,0, "}"));
					}

					else if (c == '[') {
						fichas.add(new Ficha(TipoFicha.COCHETE_ESQUERDO, 0, 0 ,0 ,0, "["));
					}

					else if (c == ']') {
						fichas.add(new Ficha(TipoFicha.COCHETE_DIREITO, 0, 0 ,0 ,0, "]"));
					}

					else if (c == '(') {
						fichas.add(new Ficha(TipoFicha.PARENTESE_ESQUERDO, 0, 0 ,0 ,0, "("));
					}

					else if (c == ')') {
						fichas.add(new Ficha(TipoFicha.PARENTESE_DIREITO, 0, 0 ,0 ,0, ")"));
					}

					else if (c == '.') {
						fichas.add(new Ficha(TipoFicha.PONTO, 0, 0 ,0 ,0, "."));
					}

					else if (c == ';') {
						fichas.add(new Ficha(TipoFicha.PONTO_VIRGULA, 0, 0 ,0 ,0, ";"));
					}

					else if (c == ':') {
						fichas.add(new Ficha(TipoFicha.DOIS_PONTOS, 0, 0 ,0 ,0, ":"));
					}

					else if (c == '?') {
						fichas.add(new Ficha(TipoFicha.TERNARIO, 0, 0 ,0 ,0, "?"));
					}

					/* Inicio dp reconhecimento de operadores logicos */
					else if (c == '^') {
						fichas.add(new Ficha(TipoFicha.XOU, 0, 0 ,0 ,0, "^"));
					}

					else if (c == '&') {
						estado = EstadoIntermediario.RECONHECENDO_E;
						ficha_inicio = p_atual;
					}

					else if (c == '|') {
						estado = EstadoIntermediario.RECONHECENDO_OU;
						ficha_inicio = p_atual;
					}

					/* Interseccao entre os operadores logicos e de comparacao */
					else if (c == '!') {
						estado = EstadoIntermediario.RECONHECENDO_EXCLAMACAO;
						ficha_inicio = p_atual;
					}

					/* De comparacao */
					else if (c == '<') {
						estado = EstadoIntermediario.RECONHECENDO_MENOR;
						ficha_inicio = p_atual;
					}

					else if (c == '=') {
						estado = EstadoIntermediario.RECONHECENDO_IGUAL;
						ficha_inicio = p_atual;
					}

					else if (c == '>') {
						estado = EstadoIntermediario.RECONHECENDO_MAIOR;
						ficha_inicio = p_atual;
					}

					else {
						fichas.add(new Ficha(TipoFicha.ERRO_LEXICO, 0, 0 ,0 ,0, reconhecido.toString()+c));
					}

					break;
					
				case RECONHECENDO_IDENTIFICADOR:
					if ((c > 0x40 && c < 0x5B) || (c > 0x60 && c < 0x7B) || (c > 0x2F && c < 0x3A)  || c == '_') {
						break;
					}

					estado = EstadoIntermediario.INICIO;
					fichas.add(new Ficha(TipoFicha.doIdentificador(reconhecido.toString()), 0, 0 ,0 ,0, reconhecido.toString()));

					l.devolverCaracter();
					break;

				/** RECONHECIMENTO DE TEXTO */
				case RECONHECENDO_TEXTO:
					salvar = true;
					if(!(c != '"' && c != '\\')) {
						if(c == '\\') { 
							estado = EstadoIntermediario.ESCAPANDO_TEXTO;
						} else if(c == '"') {
							estado = EstadoIntermediario.INICIO;
							fichas.add(new Ficha(TipoFicha.CONSTANTE_TEXTO, 0, 0 ,0 ,0, reconhecido.toString()));
						}
					}

					break;

				case ESCAPANDO_TEXTO:
					if (c < ' ' && c != '\t') {
						estado = EstadoIntermediario.ERRO;
						break;
					}

					estado = EstadoIntermediario.RECONHECENDO_TEXTO;
					break;

				/** RECONHECIMENTO DE NUMEROS */
				case RECONHECENDO_INTEIRO:
					if (c == '.') {
						estado = EstadoIntermediario.RECONHECENDO_REAL;
					} else if (!(c > 0x2F && c < 0x3A)) {
						estado = EstadoIntermediario.INICIO;
						fichas.add(new Ficha(TipoFicha.CONSTANTE_INTEIRA, 0, 0 ,0 ,0, reconhecido.toString()));
						l.devolverCaracter();;
					}

					break;

				case RECONHECENDO_REAL:
					if (!(c > 0x2F && c < 0x3A)) {
						estado = EstadoIntermediario.INICIO;
						fichas.add(new Ficha(TipoFicha.CONSTANTE_REAL, 0, 0 ,0 ,0, reconhecido.toString()));
						l.devolverCaracter();;
					}

					break;

				/** RECONHECIMENTO DE OPERADORES ARITIMETICOS **/

				case RECONHECENDO_MAIS:
					estado = EstadoIntermediario.INICIO;

					if (c == '+') {
						fichas.add(new Ficha(TipoFicha.INCREMENTO, 0, 0 ,0 ,0, "++"));
					} else if (c == '=') {
						fichas.add(new Ficha(TipoFicha.MAIS_IGUAL, 0, 0 ,0 ,0, "+="));
					} else {
						fichas.add(new Ficha(TipoFicha.MAIS, 0, 0 ,0 ,0, "+"));
						l.devolverCaracter();
					}
					break;

				case RECONHECENDO_MENOS:
					estado = EstadoIntermediario.INICIO;

					if (c == '-') {
						fichas.add(new Ficha(TipoFicha.DECREMENTO, 0, 0 ,0 ,0, "--"));
					} else if (c == '=') {
						fichas.add(new Ficha(TipoFicha.MENOS_IGUAL, 0, 0 ,0 ,0, "-="));
					} else {
						fichas.add(new Ficha(TipoFicha.MENOS, 0, 0 ,0 ,0, "-"));
						l.devolverCaracter();
					}
					break;

				case RECONHECENDO_VEZES:
					estado = EstadoIntermediario.INICIO;

					if (c == '=') {
						fichas.add(new Ficha(TipoFicha.VEZES_IGUAL, 0, 0 ,0 ,0, "*="));
					} else {
						fichas.add(new Ficha(TipoFicha.VEZES, 0, 0 ,0 ,0, "*"));
						l.devolverCaracter();
					}
					break;

				case RECONHECENDO_DIVIDIDO:
					estado = EstadoIntermediario.INICIO;

					if (c == '=') {
						fichas.add(new Ficha(TipoFicha.DIVIDIDO_IGUAL, 0, 0 ,0 ,0, "/="));
					} else if (c == '*') {
						estado = EstadoIntermediario.RECONHECENDO_COMENTARIO_A;
						salvar = false;
					} else {
						fichas.add(new Ficha(TipoFicha.DIVIDIDO, 0, 0 ,0 ,0, "/"));
						l.devolverCaracter();
					}

					break;

				/** LOGICOS **/
				case RECONHECENDO_E:
					estado = EstadoIntermediario.INICIO;

					if (c == '&') {
						fichas.add(new Ficha(TipoFicha.E, 0, 0 ,0 ,0, "&&"));
					} else {
						l.devolverCaracter();
					}
					break;

				case RECONHECENDO_OU:
					estado = EstadoIntermediario.INICIO;

					if (c == '|') {
						fichas.add(new Ficha(TipoFicha.OU, 0, 0 ,0 ,0, "||"));
					} else {
						l.devolverCaracter();
					}
					break;

				/** INTERSECCAO ENTRE OS OPERADORES LOGICOS E DE COMPARACAO */
				/* O caso exclamacao */
				case RECONHECENDO_EXCLAMACAO:
					estado = EstadoIntermediario.INICIO;

					if (c == '=') {
						fichas.add(new Ficha(TipoFicha.DIFERENTE, 0, 0 ,0 ,0, "!="));
					} else {
						fichas.add(new Ficha(TipoFicha.NAO, 0, 0 ,0 ,0, "!"));
						l.devolverCaracter();
					}
					break;

				/** DE COMPARACAO */
				case RECONHECENDO_MENOR:
					estado = EstadoIntermediario.INICIO;

					if (c == '>') {
						fichas.add(new Ficha(TipoFicha.DIFERENTE, 0, 0 ,0 ,0, "<>"));
					} else if (c == '=') {
						fichas.add(new Ficha(TipoFicha.MENOR_IGUAL, 0, 0 ,0 ,0, "<="));
					} else {
						fichas.add(new Ficha(TipoFicha.MENOR_QUE, 0, 0 ,0 ,0, "<"));
						l.devolverCaracter();
					}
					break;

				case RECONHECENDO_IGUAL:
					estado = EstadoIntermediario.INICIO;

					if (c == '=') {
						fichas.add(new Ficha(TipoFicha.IGUAL, 0, 0 ,0 ,0, "=="));
					} else {
						fichas.add(new Ficha(TipoFicha.ATRIBUICAO, 0, 0 ,0 ,0,"="));
						l.devolverCaracter();
					}
					break;

				case RECONHECENDO_MAIOR:
					estado = EstadoIntermediario.INICIO;

					if (c == '<') {
						fichas.add(new Ficha(TipoFicha.TROCA, 0, 0 ,0 ,0, "><"));
					} else if (c == '=') {
						fichas.add(new Ficha(TipoFicha.MAIOR_IGUAL, 0, 0 ,0 ,0, ">="));
					} else {
						fichas.add(new Ficha(TipoFicha.MAIOR_QUE, 0, 0 ,0 ,0, ">"));
						l.devolverCaracter();
					}
					break;

				case RECONHECENDO_COMENTARIO_A:
					if (c == '*') {
						estado = EstadoIntermediario.RECONHECENDO_COMENTARIO_B;
					}
					break;

				case RECONHECENDO_COMENTARIO_B:
					if (c == '/') {
						estado = EstadoIntermediario.INICIO;
					} else {
						estado = EstadoIntermediario.RECONHECENDO_COMENTARIO_A;
					}
					break;

				/** ESTADOS DE ERRO **/
				case ERRO:
					fichas.add(new Ficha(TipoFicha.ERRO_LEXICO, 0, 0 ,0 ,0, reconhecido.toString()));
					break;
			} // switch

			if (salvar)
				reconhecido.append(c);
		}
		

		for(Ficha f : fichas)
			System.out.println("Reconheceu: " +f.fragmento+" foi reconhecido como "+ f.tipoFicha );
	}
}
